import { App, Frame } from "leafer-ui";
import { TextBox } from "../types";
// /**
//  * @description 模拟浏览器 选择文本
//  *  1.找到起始命中TextBox；
//  * 2.找到结束命中TextBox；如果找不到，则找距离结束点最近的TextBox（如果有两页则在结束点所处页寻找最近TextBox）;
//  * 3.根据起始TextBox和结束TextBox,截取中间所有TextBox作为选择结果；
//  * @returns
//  */
// export function getSelectedTextBoxes(params: {
//   startX: number;
//   startY: number;
//   currentX: number;
//   currentY: number;
//   boxes: TextBox[][];
//   target: (pageIndex?: number) => Frame;
//   app: App;
// }) {
//   const selectedTextBoxes: TextBox[] = [];
//   const selectedTextBoxMap = new Map<string | number, TextBox>();
//   const ranges: { startTextBox: TextBox; endTextBox: TextBox }[] = [];
//   const { startX, startY, currentX, currentY, boxes, target, app } = params;

//   // 判断点是否在 box 内部
//   function isPointInBox(x: number, y: number, box: TextBox): boolean {
//     return (
//       x >= box.x &&
//       x <= box.x + box.width &&
//       y >= box.y &&
//       y <= box.y + box.height
//     );
//   }

//   // 工具函数：全局坐标转页面本地坐标
//   function toLocal(
//     x: number,
//     y: number,
//     pageIndex: number
//   ): { x: number; y: number } {
//     if (pageIndex === -1) return { x, y };
//     return target(pageIndex).getBoxPoint(
//       app.tree.getWorldPointByPage({ x, y })
//     );
//   }

//   // 查找命中 TextBox
//   function findHitBox(
//     x: number,
//     y: number,
//     pages: TextBox[][]
//   ): { box: TextBox | null; pageIndex: number } {
//     for (let i = 0; i < pages.length; i++) {
//       const pos = toLocal(x, y, i);
//       for (const box of pages[i]) {
//         if (isPointInBox(pos.x, pos.y, box)) {
//           return { box, pageIndex: i };
//         }
//       }
//     }
//     return { box: null, pageIndex: -1 };
//   }

//   // 查找最近的 TextBox（增加距离阈值）
//   const MAX_DISTANCE = 50; // 像素
//   function findClosestBox(
//     x: number,
//     y: number,
//     candidates: TextBox[],
//     pageIndex: number
//   ): TextBox | null {
//     if (candidates.length === 0) return null;

//     let closestBox: TextBox | null = null;
//     let minDistance = Infinity;
//     const pos = toLocal(x, y, pageIndex); // 结束点在当前页的本地坐标

//     for (const box of candidates) {
//       const boxCenterX = box.x + box.width / 2;
//       const boxCenterY = box.y + box.height / 2;

//       const dx = pos.x - boxCenterX;
//       const dy = pos.y - boxCenterY;
//       const distance = Math.sqrt(dx * dx + dy * dy);

//       if (distance < minDistance) {
//         minDistance = distance;
//         closestBox = box;
//       }
//     }

//     return closestBox;
//   }
//   // 查找点击点所在的页面索引
//   function findPageByPoint(x: number, y: number): number {
//     for (let i = 0; i < boxes.length; i++) {
//       const pageFrame = target(i);
//       const localPos = pageFrame.getBoxPoint(
//         app.tree.getWorldPointByPage({ x, y })
//       );
//       // 假设每个页面 Frame 的尺寸足够大能容纳所有 TextBox，直接判断是否在 Frame 内部
//       if (
//         localPos.x >= 0 &&
//         localPos.x <= pageFrame.width &&
//         localPos.y >= 0 &&
//         localPos.y <= pageFrame.height
//       ) {
//         return i;
//       }
//     }
//     return -1; // 没有找到对应的页面
//   }

//   // 步骤 1：查找起始命中 TextBox
//   const { box: startBox, pageIndex: startPageIndex } = findHitBox(
//     startX,
//     startY,
//     boxes
//   );
//   if (!startBox) return { selectedTextBoxes, selectedTextBoxMap, ranges };

//   // 步骤 2：查找结束命中 TextBox 或最近的 TextBox
//   const { box: endBox, pageIndex: endPageIndex } = findHitBox(
//     currentX,
//     currentY,
//     boxes
//   );
//   let finalEndBox: TextBox | null = endBox;
//   let finalPageIndex: number = endPageIndex;
//   if (!finalEndBox) {
//     // 先确定结束点所在页面
//     const hitPageIndex = findPageByPoint(currentX, currentY);
//     const targetPageIndex = hitPageIndex !== -1 ? hitPageIndex : startPageIndex;
//     finalPageIndex = targetPageIndex;
//     const searchCandidates = boxes[targetPageIndex];
//     finalEndBox =
//       findClosestBox(currentX, currentY, searchCandidates, targetPageIndex) ||
//       null;
//   }

//   if (!finalEndBox) return { selectedTextBoxes, selectedTextBoxMap, ranges };
//   // 步骤 3：获取起始和结束之间的所有 TextBox（统一为正向选择）

//   const startIndex = startBox.getAttr("data").index;
//   const endIndex = finalEndBox.getAttr("data").index;

//   let startPageIndexFinal = startPageIndex;
//   let endPageIndexFinal = finalPageIndex;

//   let currentStartBox = startBox;
//   let currentEndBox = finalEndBox;

//   // 如果起始 index > 结束 index 或起始页 > 结束页，说明是反向选择，交换两者
//   if (
//     startPageIndex > finalPageIndex ||
//     (startPageIndex === finalPageIndex && startIndex > endIndex)
//   ) {
//     [currentStartBox, currentEndBox] = [currentEndBox, currentStartBox];
//     [startPageIndexFinal, endPageIndexFinal] = [
//       endPageIndexFinal,
//       startPageIndexFinal,
//     ];
//   }
//   const newStartIndex = currentStartBox.getAttr("data").index;
//   const newEndIndex = currentEndBox.getAttr("data").index;

//   let targetBoxes: TextBox[] = [];

//   const startPage = Math.min(startPageIndexFinal, endPageIndexFinal);
//   const endPage = Math.max(startPageIndexFinal, endPageIndexFinal);

//   for (let i = startPage; i <= endPage; i++) {
//     const pageBoxes = boxes[i];
//     if (!pageBoxes || pageBoxes.length === 0) continue;

//     const firstIndex = 0;
//     const lastIndex = pageBoxes.length - 1;

//     let startIdx = firstIndex;
//     let endIdx = lastIndex;

//     if (i === startPageIndexFinal) {
//       startIdx = newStartIndex;
//     }

//     if (i === endPageIndexFinal) {
//       endIdx = newEndIndex;
//     }

//     // 因为我们已经保证了顺序一致，所以这里只需正向取
//     if (startIdx <= endIdx) {
//       targetBoxes = targetBoxes.concat(pageBoxes.slice(startIdx, endIdx + 1));
//     }
//   }

//   selectedTextBoxes.push(...targetBoxes);

//   // 构建 Map
//   for (const box of targetBoxes) {
//     selectedTextBoxMap.set(box.id, box);
//   }

//   ranges.push({ startTextBox: currentStartBox, endTextBox: currentEndBox });

//   return { selectedTextBoxes, selectedTextBoxMap, ranges };
// }

/**
 * @description 模拟浏览器选择文本
 * 1. 找到起始命中 TextBox
 * 2. 找到结束命中 TextBox（找不到则找最近）
 * 3. 获取起始和结束之间的所有 TextBox
 */
export function getSelectedTextBoxes(params: {
  startX: number;
  startY: number;
  currentX: number;
  currentY: number;
  boxes: TextBox[][];
  target: (pageIndex?: number) => Frame;
  app: App;
}) {
  const { startX, startY, currentX, currentY, boxes, target, app } = params;
  const result = {
    selectedTextBoxes: [] as TextBox[],
    selectedTextBoxMap: new Map<string | number, TextBox>(),
    ranges: [] as { startTextBox: TextBox; endTextBox: TextBox }[],
  };

  // 边界检查：无文本框时直接返回
  if (!boxes.length || boxes.every((page) => !page.length)) return result;

  // ----------------------------
  // 工具函数优化
  // ----------------------------
  const isPointInBox = (x: number, y: number, box: TextBox): boolean =>
    x >= box.x &&
    x <= box.x + box.width &&
    y >= box.y &&
    y <= box.y + box.height;

  const toLocal = (x: number, y: number, pageIndex: number) =>
    pageIndex === -1
      ? { x, y }
      : target(pageIndex).getBoxPoint(app.tree.getWorldPointByPage({ x, y }));

  const findHitBox = (x: number, y: number, pages: TextBox[][]) => {
    for (let i = 0; i < pages.length; i++) {
      const pos = toLocal(x, y, i);
      for (const box of pages[i]) {
        if (isPointInBox(pos.x, pos.y, box)) {
          return { box, pageIndex: i };
        }
      }
    }
    return { box: null, pageIndex: -1 };
  };

  const findClosestBox = (
    x: number,
    y: number,
    candidates: TextBox[],
    pageIndex: number
  ) => {
    if (!candidates.length) return null;

    let closestBox: TextBox | null = null;
    let minDistance = Infinity;
    const pos = toLocal(x, y, pageIndex);

    for (const box of candidates) {
      const boxCenterX = box.x + box.width / 2;
      const boxCenterY = box.y + box.height / 2;
      const dx = pos.x - boxCenterX;
      const dy = pos.y - boxCenterY;
      const distance = dx * dx + dy * dy; // 使用平方避免开方运算

      if (distance < minDistance) {
        minDistance = distance;
        closestBox = box;
      }
    }

    return closestBox;
  };

  const findPageByPoint = (x: number, y: number) => {
    for (let i = 0; i < boxes.length; i++) {
      const pageFrame = target(i);
      const localPos = pageFrame.getBoxPoint(
        app.tree.getWorldPointByPage({ x, y })
      );

      // 检查点是否在页面内
      if (
        localPos.x >= 0 &&
        localPos.x <= pageFrame.width &&
        localPos.y >= 0 &&
        localPos.y <= pageFrame.height
      ) {
        return i;
      }
    }
    return -1;
  };

  // ----------------------------
  // 主逻辑优化
  // ----------------------------
  // 步骤1: 查找起始命中框
  const startResult = findHitBox(startX, startY, boxes);
  if (!startResult.box) return result;
  const { box: startBox, pageIndex: startPageIndex } = startResult;

  // 步骤2: 查找结束命中框
  const endResult = findHitBox(currentX, currentY, boxes);
  let finalEndBox: TextBox | null = endResult.box;
  let finalPageIndex = endResult.pageIndex;

  // 未命中则查找最近的文本框
  if (!finalEndBox) {
    const hitPageIndex = findPageByPoint(currentX, currentY);
    const targetPageIndex = hitPageIndex !== -1 ? hitPageIndex : startPageIndex;
    finalPageIndex = targetPageIndex;
    finalEndBox = findClosestBox(
      currentX,
      currentY,
      boxes[targetPageIndex] || [],
      targetPageIndex
    );
  }
  if (!finalEndBox) return result;

  // 缓存索引避免重复访问属性
  const startIndex = startBox.getAttr("data").index;
  const endIndex = finalEndBox.getAttr("data").index;

  // 处理反向选择
  const isReverseSelection =
    startPageIndex > finalPageIndex ||
    (startPageIndex === finalPageIndex && startIndex > endIndex);

  const [startBoxFinal, endBoxFinal] = isReverseSelection
    ? [finalEndBox, startBox]
    : [startBox, finalEndBox];

  const [startPageFinal, endPageFinal] = isReverseSelection
    ? [finalPageIndex, startPageIndex]
    : [startPageIndex, finalPageIndex];

  const startIdxFinal = startBoxFinal.getAttr("data").index;
  const endIdxFinal = endBoxFinal.getAttr("data").index;

  // 步骤3: 收集选中文本框
  const startPage = Math.min(startPageFinal, endPageFinal);
  const endPage = Math.max(startPageFinal, endPageFinal);

  for (let i = startPage; i <= endPage; i++) {
    const pageBoxes = boxes[i];
    if (!pageBoxes?.length) continue;

    const startIdx = i === startPageFinal ? startIdxFinal : 0;
    const endIdx = i === endPageFinal ? endIdxFinal : pageBoxes.length - 1;

    if (startIdx <= endIdx) {
      const slice = pageBoxes.slice(startIdx, endIdx + 1);
      result.selectedTextBoxes.push(...slice);
    }
  }

  // 构建Map和范围
  for (const box of result.selectedTextBoxes) {
    result.selectedTextBoxMap.set(box.id, box);
  }

  result.ranges.push({
    startTextBox: startBoxFinal,
    endTextBox: endBoxFinal,
  });

  return result;
}
